/**
 * @file STL_RtspResParser.cpp
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-02-18
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#include "STL_RtspResParser.h"
#include "STL_Text.h"
#include "STLOG.h"
#include <regex>

namespace STL
{
    void STL_RtspResParser::parse()
    {
        do
        {
            if (m_status == Wait_Response_Status_Line)
            {
                std::regex s_regStatusLine("(RTSP/[\\d]{1}\\.[\\d]{1}) (\\d+) (\\S+)\\r\\n");
                std::smatch result;
                if (std::regex_search(m_data, result, s_regStatusLine))
                {
                    m_response.reset(new STL_RtspResponse());
                    m_response->m_version = result.str(1);
                    m_response->m_code = std::stoi(result.str(2));
                    m_response->m_phrase = result.str(3);
                    m_response->m_headers.clear();
                    m_response->m_body.clear();
                    m_body_lenght = 0;
                    m_data = result.suffix();
                    m_status = Wait_Response_Header;
                }
                else
                {
                    //Status-Line = RTSP-Version SP Status-Code SP Reason-Phrase CRLF
                    if (m_data.size() > 128) // 8(version) + 1(space) +  3(code) + 1(space) + ?(Phrase) + 2(\r\n)
                    {
                        m_data = m_data.substr(m_data.size() - 128);
                    }
                    break;
                }
            }
            if (m_status == Wait_Response_Header)
            {
                size_t pos = m_data.find("\r\n\r\n");
                if (pos == std::string::npos)
                {
                    if (m_data.size() > 10240)
                    {
                        stlog_warn("headers > 10240");
                        m_status = Wait_Response_Status_Line;
                        continue;
                    }
                }
                else
                {
                    std::string headers = m_data.substr(0, pos);
                    m_data = m_data.substr(pos + 4);
                    auto headerLines = STL_Text::split(headers, "\r\n");
                    bool isParseError = false;
                    for (size_t i = 0; i < headerLines.size(); i++)
                    {
                        auto key_value = STL_Text::split(headerLines.at(i), ": ");
                        if (key_value.size() < 2)
                        {
                            stlog_warn("headers > key_value warn %s", headerLines.at(i).c_str());
                            isParseError = true;
                            break;
                        }
                        std::string key = key_value.at(0);
                        std::string value = key_value.at(1);
                        if (STL_Text::toLowerStr(key) == "content-length")
                        {
                            m_body_lenght = std::stoul(value);
                            if (m_body_lenght > 1024 * 1024 * 16)
                            {
                                stlog_warn("headers > m_body_lenght > 16M [%zu]", m_body_lenght);
                            }
                        }
                        m_response->m_headers[key] = value;
                    }
                    if (isParseError)
                    {
                        m_status = Wait_Response_Status_Line;
                        continue;
                    }
                    if (m_body_lenght > 0)
                    {
                        m_status = Wait_Response_Body;
                    }
                    else
                    {
                        stlog_debug("rtsp info without body!!!!\n");
                        if (m_responseCallback)
                        {
                            m_responseCallback(m_response);
                        }
                        m_status = Wait_Response_Status_Line;
                        continue;
                    }
                }
            }
            if (m_status == Wait_Response_Body)
            {
                if (m_data.size() >= m_body_lenght)
                {
                    m_response->m_body = m_data.substr(0, m_body_lenght);
                    m_data = m_data.substr(m_body_lenght);
                    stlog_debug("rtsp info with body!!!!\n");
                    if (m_responseCallback)
                    {
                        m_responseCallback(m_response);
                    }
                    m_status = Wait_Response_Status_Line;
                    continue;
                }
            }

        } while (1);
    }
    // void STL_RtspResParser::parseUri()
    // {
    //     std::string url = m_response->m_uri;
    //     size_t pos = 0;
    //     std::string flag;

    //     size_t start_path = pos;
    //     size_t end_path = url.find_first_of(";?#", pos);
    //     if (end_path != std::string::npos)
    //     {
    //         m_response->m_path = url.substr(start_path, end_path - start_path);
    //         flag = url.substr(end_path, 1);
    //         pos = end_path + 1;
    //     }
    //     else
    //     {
    //         m_response->m_path = url.substr(start_path);
    //         return;
    //     }
    //     if (flag == ";")
    //     {
    //         size_t start_parameter = pos;
    //         size_t end_parameter = url.find_first_of("?#", pos);
    //         if (end_parameter != std::string::npos)
    //         {
    //             m_response->m_parameter = url.substr(start_parameter, end_parameter - start_parameter);
    //             flag = url.substr(end_parameter, 1);
    //             pos = end_parameter + 1;
    //         }
    //         else
    //         {
    //             m_response->m_parameter = url.substr(start_parameter);
    //             return;
    //         }
    //     }
    //     if (flag == "?")
    //     {
    //         size_t start_query = pos;
    //         size_t end_query = url.find_first_of("#", pos);
    //         if (end_query != std::string::npos)
    //         {
    //             m_response->m_query = url.substr(start_query, end_query - start_query);
    //             parseQuery();
    //             flag = url.substr(end_query, 1);
    //             pos = end_query + 1;
    //         }
    //         else
    //         {
    //             m_response->m_query = url.substr(start_query);
    //             parseQuery();
    //             return;
    //         }
    //     }
    //     m_response->m_fragment = url.substr(pos);
    // }
    // void STL_RtspResParser::parseQuery()
    // {
    //     if (m_response->m_query.empty())
    //         return;
    //     std::string query = m_response->m_query;
    //     auto values = STL_Text::split(query, "&");
    //     for (size_t i = 0; i < values.size(); i++)
    //     {
    //         if (values.at(i).empty())
    //             continue;
    //         auto key_value = STL_Text::split(values.at(i), "=");
    //         std::string key = key_value.at(0);
    //         std::string value = "";
    //         if (key_value.size() >= 2)
    //         {
    //             value = key_value.at(1);
    //         }
    //         m_response->m_query_map[key] = value;
    //     }
    // }
} // namespace STL
